package rubik;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import rubik.crossover.CogwheelCrossOver;
import rubik.crossover.ICrossOverFunc;
import rubik.crossover.RandomCrossOver;
import rubik.crossover.RandomMargeCrossOver;
import rubik.crossover.RandomSingleIndexCrossOver;
import rubik.fitness.ConflictsFitness;
import rubik.fitness.EdgesCornersFitness;
import rubik.fitness.IFitnessFunc;
import rubik.mutators.ICubeSolutionMutator;
import rubik.mutators.LastSeqMutator;
import rubik.mutators.RandomSeqMutator;
import rubik.seqs.ISequenceGenerator;
import rubik.seqs.RandomSeqGenerator;
import au.com.bytecode.opencsv.CSVWriter;
import evo.Evolution;
import evo.IInstance;
import evo.selectors.ElitistSelector;
import evo.selectors.ISelector;
import evo.selectors.TournamentSelector;

public class Run {

	public static void main(String[] args) {

		int printEvery = 100;

		int randMoves = 10;

		int generations = 100;
		int population = 200;
		double[] pmutates = new double[] { 0.1, 0.2, 0.4, 0.6, 0.8, 0.9 };

		double[] pcrossovers = new double[] { 0.1, 0.2, 0.4, 0.6, 0.8, 0.9 };

		ISequenceGenerator[] seqgens = new ISequenceGenerator[] { new RandomSeqGenerator(
				3) };

		ICubeSolutionMutator[] mutators = new ICubeSolutionMutator[] {
				new LastSeqMutator(), new RandomSeqMutator() };

		IFitnessFunc[] fitnessFuncs = new IFitnessFunc[] {
				new ConflictsFitness(), new EdgesCornersFitness() };

		ICrossOverFunc[] crossovers = new ICrossOverFunc[] {
				new RandomSingleIndexCrossOver(),
				new RandomMargeCrossOver(),
				//new ConcatenationCrossOver(),
				new CogwheelCrossOver(),
				new RandomCrossOver() };

		ISelector[] selectors = new ISelector[] { new TournamentSelector(), new ElitistSelector() };
		
		int reps = 3;
		
		int counter = 0;
		int total = pmutates.length * pcrossovers.length * seqgens.length * mutators.length * fitnessFuncs.length * crossovers.length * selectors.length; 

		
		File fout = new File("output.csv");
		CSVWriter w = null;
		try {
			if (!fout.exists())
				fout.createNewFile();
			w = new CSVWriter(new FileWriter(fout));
		} catch (IOException e) {
			e.printStackTrace();
			return;
		}
		String[] headers = "population,generations,seqgen,mutator,fitness,crossover,selector,mutateP,crossoverP,gen,best,avg,var"
				.split(",");
		w.writeNext(headers);
		for (int k = 0; k < reps; k++) {
			Cube cube = new Cube();
			cube.randomize(randMoves);
			for (ISelector selector : selectors) {
				for (ICrossOverFunc crossover : crossovers) {
					for (ISequenceGenerator seqgen : seqgens) {
						for (ICubeSolutionMutator mutator : mutators) {
							for (IFitnessFunc fitnessFunc : fitnessFuncs) {

								CubeBuilder builder = new CubeBuilder(cube,
										mutator, seqgen, fitnessFunc, crossover);

								for (double pmutate : pmutates) {
									for (double pcrossover : pcrossovers) {
										
										counter++;
										System.out.println(String.format("%d/%d",counter, total));

										Evolution evo = new Evolution(builder,
												population, pmutate,
												pcrossover, selector);

										for (int i = 1; i <= generations; i++) {
											IInstance instance = evo
													.getBestInstance();
											String outstr = String
													.format("%d,%d,%s,%s,%s,%s,%s,%.2f,%.2f,%d,%.2f,%.2f,%.2f",
															population,
															generations,
															seqgen.getClass()
															.getName(),
															mutator.getClass()
															.getName(),
															fitnessFunc
															.getClass()
															.getName(),
															crossover
															.getClass()
															.getName(),
															selector.getClass()
															.getName(),
															pmutate,
															pcrossover,
															i,
															(instance
																	.getFitness() / fitnessFunc
																	.getMaxFitness()) * 100,
																	(evo.getAverageFitness() / fitnessFunc
																			.getMaxFitness()) * 100,
																			(evo.getVarianceFitness() / fitnessFunc
																					.getMaxFitness()) * 100);
											w.writeNext(outstr.split(","));
											if (i % printEvery == 0) {
												/*
												System.out
														.println(String
																.format("%d) best: %.2f average: %.2f variance: %.2f genSize: %d  [%s]",
																		i,
																		instance.getFitness(),
																		evo.getAverageFitness(),
																		evo.getVarianceFitness(),
																		evo.getCurrentGen()
																				.size(),
																		instance));
																		*/
												System.out
														.println(outstr);
											}
											// System.out.print(".");

											evo.advanceGen();
										}
										System.gc();
									}
									System.out.println();
								}
							}
						}
					}
				}
			}
		}
		try {
			w.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println("bye!");
	}
}
